<template>
  <div class="skybox">
    <div class="title">
      <el-radio-group v-model="intensity">
        <el-radio-button value="0.5" @change="setLightIntensity(0.3)">暗</el-radio-button>
        <el-radio-button value="1.5" @change="setLightIntensity(0.6)">正常</el-radio-button>
        <el-radio-button value="2.5" @change="setLightIntensity(1)">亮</el-radio-button>
      </el-radio-group>
    </div>
    <div ref="refDom" class="model-view">
    </div>
  </div>
</template>

<script setup>
import {useTemplateRef} from 'vue'
import * as THREE from 'three'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import Stats from 'three/examples/jsm/libs/stats.module.js'
import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js'
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js'

defineOptions({
  name: 'threejs'
})
const intensity = ref(0.6)
const refDom = useTemplateRef('refDom')
let DOM, scene, camera, renderer, controls, frameStats, ambientLight
const gltfLoader = new GLTFLoader()
onMounted(() => {
  DOM = refDom.value
  initScene()
  initCamera()
  initRender()
  initControls()
  initLight()
  initFrameStats()
  createGeometry()
  // initHelpers()
  render()
})
// 初始化场景
const initScene = () => {
  scene = new THREE.Scene()
  // 地板
  const planeSize = 50
  const loader = new THREE.TextureLoader()
  const texture = loader.load(`${import.meta.env.VITE_THREEJS_BASE_URL}/images/checker.png`)
  // THREE.RepeatWrapping 纹理重复
  texture.wrapS = THREE.RepeatWrapping
  texture.wrapT = THREE.RepeatWrapping
  // 当一个纹素覆盖大于一个像素时，贴图将如何采样。 THREE.NearestFilter，它将使用最接近的纹素的值。
  texture.magFilter = THREE.NearestFilter
  const repeats = planeSize
  // 重复次数
  texture.repeat.set(repeats, repeats)
  const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize)
  // Phong材质
  const planeMat = new THREE.MeshPhongMaterial({
    map: texture,
    side: THREE.DoubleSide
  })
  const mesh = new THREE.Mesh(planeGeo, planeMat)
  mesh.rotation.x = Math.PI * -0.5
  scene.add(mesh)
}
// 初始化相机
const initCamera = () => {
  camera = new THREE.PerspectiveCamera(50, refDom.value.clientWidth / refDom.value.clientHeight, 0.1, 1000)
  camera.position.set(0, 5, -15)
  camera.lookAt(0, 0, 0)
}
// 初始化渲染器
const initRender = () => {
  renderer = new THREE.WebGLRenderer({
    antialias: true, // 抗锯齿
    alpha: true//背景色透明
  })
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.toneMapping = THREE.ACESFilmicToneMapping
  renderer.toneMappingExposure = 1
  renderer.setSize(DOM.clientWidth, DOM.clientHeight)
  DOM.appendChild(renderer.domElement)
}
// 初始化控制器
const initControls = () => {
  controls = new OrbitControls(camera, renderer.domElement) // 鼠标控制
  controls.enableDamping = true // 设置阻尼
  controls.update()
}

const initHelpers = () => {
  scene.add(new THREE.AxesHelper(100)) // xyz轴辅助线
}
const initLight = () => {
  ambientLight = new THREE.AmbientLight(0xffffff, 1) // 环境光
  scene.add(ambientLight)

}
const setLightIntensity = (val) => {
  intensity.value = val
  ambientLight.intensity = val
}
// 创建性能监视器
const initFrameStats = () => {
  frameStats = new Stats()
  frameStats.setMode(0)// 设置监视器面板，传入面板id（0: fps, 1: ms, 2: mb）
  // 设置监视器位置
  frameStats.domElement.style.position = 'absolute'
  frameStats.domElement.style.left = '0px'
  frameStats.domElement.style.top = '0px'
  // 将监视器添加到页面中
  DOM.appendChild(frameStats.domElement)
}

const podiumGroup = new THREE.Group()
const createGeometry = () => {
  const formIntoGroups = new THREE.Group()
  const array = Array.from({length: 9}, (_, i) => i - 4)
  const colGroups = new THREE.Group()
  gltfLoader.load(`${import.meta.env.VITE_THREEJS_BASE_URL}/soldier/soldier.glb`, (gltf) => {
    let model = gltf.scene
    array.forEach((num, i) => {
      let mesh = SkeletonUtils.clone(model)
      mesh.position.set(num * 1.85, 0, 0)
      colGroups.add(mesh)
      // mesh.name = `士兵 ${i + 1}`
    })
    array.forEach((num, i) => {
      let mesh = SkeletonUtils.clone(colGroups)
      mesh.position.set(0, 0, num * 1.85)
      formIntoGroups.add(mesh)
    })
    formIntoGroups.add(colGroups)
    scene.add(formIntoGroups)
  })
}
const render = () => {
  frameStats.update()// 更新帧数
  renderer.render(scene, camera)
  // geoGroup.rotateY(Math.PI / 180)
  requestAnimationFrame(render)
}
</script>

<style lang="scss" scoped>
.skybox {
  width: 100%;
  height: 100%;

  .title {
    height: 30px;
    line-height: 30px;
    margin-bottom: 10px;
  }

  .model-view {
    position: relative;
    width: 100%;
    height: calc(100% - 40px);
  }
}
</style>
